Skip to content

Take the marketplace through the API, and stop pinning versions - #10

Merged
nicodes merged 1 commit into
mainfrom
marketplace-through-the-api
Aug 3, 2026
Merged

Take the marketplace through the API, and stop pinning versions#10
nicodes merged 1 commit into
mainfrom
marketplace-through-the-api

Conversation

@nicodes

@nicodes nicodes commented Aug 3, 2026

Copy link
Copy Markdown
Member

Reopens #8, which GitHub auto-closed when its base branch was deleted on merging #7. Same commit, rebased onto main; the diff is unchanged.

Client half of taking the marketplace through the API. Pairs with aviorstudio/termcade-be#6.

Packages come through the registry

Fetch is gone. Download resolves and then streams from an authed endpoint on the API, with the session attached.

That is what makes "installing requires an account" true rather than merely enforced in this client — before #7 the TUI install path was fully anonymous and the CLI let marketplace ids through unauthenticated, and even after it, anything holding a resolve response could fetch the asset directly. It also gives the Expo app the same path the arcade uses instead of a second one to build.

Still a product boundary, not an access control. The games are open source and their release assets are public; anyone can still fetch them. The account buys a library that follows you, not access to bytes.

The digest keeps doing real work: it ties what arrives to what the registry validated at publish time, across a hop the registry does not control. A mismatch or a missing digest is fatal.

No pinned versions

add author/slug@1.2.3 no longer resolves. Resolve no longer takes a version.

A game is not a dependency — nothing builds against one — so the reasons a package manager pins do not apply, and the two cases people would pin for (reproducing a bug report, escaping a bad release) are author problems with author solutions. The ABI still narrows the choice, but that was never about versions: the registry picks the newest release this binary can run, so a game that has moved on tells you to update termcade rather than handing you a package the host would refuse.

The old spelling gets a real answer rather than open aviorstudio/tetris@0.0.1: no such file or directory:

$ termcade add aviorstudio/tetris@0.0.1
termcade: versions cannot be pinned — `termcade add aviorstudio/tetris` installs what aviorstudio/tetris currently ships

That check runs before the account check — being told to sign in and then told the syntax changed is two trips for one mistake.

Tests

internal/registry had none, which was the wrong place for the gap: it is the trust boundary. It has five now, against a stub that answers the way the API does:

  • a package arrives through the registry, with the session attached, and the GitHub URL resolve hands out is never fetched (the stub counts hits on it)
  • a mismatched digest never reaches the disk, and leaves no temp file
  • a missing digest is refused rather than trusted
  • 401 surfaces as ErrLoginRequired, so callers can say "sign in" instead of "HTTP 401"
  • resolve sends the ABI and no version

Verification

go vet clean, full suite passes after the rebase. Checked against a clean install: pinned syntax explains itself, a marketplace id asks for an account, and the bundled three still play with no network.

🤖 Generated with Claude Code

Two changes that belong together, because both narrow what a client is
allowed to ask for.

Packages now come back through the registry instead of from GitHub.
Fetch is gone; Download resolves and then streams from an authed
endpoint on the API, with the session attached. That is what makes
"installing requires an account" true rather than merely enforced in
this client — the TUI install path was fully anonymous, and the CLI let
marketplace ids through unauthenticated — and it gives the app the same
path the arcade uses instead of a second one to build.

It is a product boundary, not an access control, and is not built as
though it were one. The games are open source and their release assets
are public; anyone can still fetch them. What the account buys is a
library that follows you and a marketplace that knows who is asking.

Pinning is gone with it. `add author/slug@1.2.3` no longer resolves,
Resolve no longer takes a version, and SelectRelease no longer matches
one. A game is not a dependency — nothing builds against one — so the
reasons a package manager pins do not apply here, and the two cases
people would pin for (reproducing a bug report, escaping a bad release)
are author problems with author solutions. The one thing that still
narrows the choice is the ABI, which was never about versions: the
registry picks the newest release this binary can run, so a game that
has moved on tells you to update termcade rather than handing you a
package the host would refuse.

Old releases stay in the store. They are a record of what was
published; nothing selects them.

The old spelling gets a real answer instead of "no such file", since it
is in READMEs and possibly in someone's scripts. That check runs before
the account check: being told to sign in and then told the syntax
changed is two trips for one mistake.

internal/registry had no tests, which was the wrong place for the gap —
it is the trust boundary. It now has five, including that a package
arrives through the registry rather than from the asset URL resolve
hands out, and that a digest mismatch never reaches the disk.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nicodes
nicodes merged commit 2c08740 into main Aug 3, 2026
1 check passed
@nicodes
nicodes deleted the marketplace-through-the-api branch August 3, 2026 01:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant